﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;


namespace TCP_Client_App
{
    public partial class FrmClient : Form
    {
        public FrmClient()
        {
            InitializeComponent();
        }

        //定义回调
        private delegate void SetTextCallBack(string strValue);
        //声明
        private SetTextCallBack setCallBack;

        //定义接收服务端发送消息的回调
        private delegate void ReceiveMsgCallBack(string strMsg);
        //声明
        private ReceiveMsgCallBack receiveCallBack;

        //创建连接的Socket
        Socket socketSend;
        //创建接收服务端发送消息的线程
        Thread threadReceive;

        private void SetValue(string strValue)
        {
            this.txt_Log.AppendText(strValue + "\r \n");
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            try
            {
                socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = IPAddress.Parse(this.txt_IP.Text.Trim());
                socketSend.Connect(ip, Convert.ToInt32(this.txt_Port.Text.Trim()));
                //实例化回调
                setCallBack = new SetTextCallBack(SetValue);
                receiveCallBack = new ReceiveMsgCallBack(SetValue);
                this.txt_Log.Invoke(setCallBack, "\r\n连接成功");
                this.txt_Log.Invoke(setCallBack, "Connect local ip: " + socketSend.LocalEndPoint.ToString());
                this.txt_Log.Invoke(setCallBack, "Connect remote ip: " + socketSend.RemoteEndPoint.ToString());

                //开启一个新的线程不停的接收服务器发送消息的线程
                threadReceive = new Thread(new ThreadStart(Receive));
                //设置为后台线程
                threadReceive.IsBackground = true;
                threadReceive.Start();
            }
            catch (Exception ex)
            {
                //MessageBox.Show("连接服务端出错:" + ex.ToString());
                this.txt_Log.Invoke(receiveCallBack, "连接服务端出错:" + ex.Message);
            }
        }


        /// <summary>
        /// 接口服务器发送的消息
        /// </summary>
        private void Receive()
        {
            try
            {
                Socket tempSocketSend = socketSend;
                this.txt_Log.Invoke(receiveCallBack, string.Format("当前你创建的会话线程id:{0}", Thread.CurrentThread.ManagedThreadId));
                while (true)
                {
                    byte[] buffer = new byte[2048];
                    //实际接收到的字节数
                    //int r = socketSend.Receive(buffer);   //不使用最新的全局socket来接收消息，
                    int r = tempSocketSend.Receive(buffer);     //而使用创建接收线程时的socket来接收消息，防止多个线程交错收到数据
                    if (r == 0)
                    {
                        break;
                    }
                    else
                    {
                        //判断发送的数据的类型
                        if (Encoding.Default.GetString(buffer, 0, 1) == "0") //表示发送的是文字消息
                        {
                            string str = Encoding.Default.GetString(buffer, 1, r - 1);
                            this.txt_Log.Invoke(receiveCallBack, string.Format("会话线程id:{2},local ip:{3} 接收远程服务端:{0}发送的消息:{1}", tempSocketSend.RemoteEndPoint, str, Thread.CurrentThread.ManagedThreadId, tempSocketSend.LocalEndPoint));
                        }
                        //表示发送的是文件
                        if (Encoding.Default.GetString(buffer, 0, 1) == "1") //表示发送的是文件
                        {
                            SaveFileDialog sfd = new SaveFileDialog();
                            sfd.InitialDirectory = @"";
                            sfd.Title = "请选择要保存的文件";
                            sfd.Filter = "所有文件|*.*";
                            sfd.ShowDialog(this);

                            string strPath = sfd.FileName;
                            using (FileStream fsWrite = new FileStream(strPath, FileMode.OpenOrCreate, FileAccess.Write))
                            {
                                fsWrite.Write(buffer, 1, r - 1);
                            }

                            this.txt_Log.Invoke(receiveCallBack, string.Format("会话线程id:{2},local ip:{3} 接收远程服务端:{0}发送的文件:{1}", socketSend.RemoteEndPoint, strPath, Thread.CurrentThread.ManagedThreadId, socketSend.LocalEndPoint));
                            MessageBox.Show("保存文件成功");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                //MessageBox.Show("接收服务端发送的消息出错:" + ex.Message);
                this.txt_Log.Invoke(receiveCallBack, string.Format("id1-{1},id2-{2} 接收服务端发送的消息出错:{0}", ex.Message, Thread.GetDomainID(), Thread.CurrentThread.ManagedThreadId));
            }
        }


        /// <summary>
        /// 客户端给服务器发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Send_Click(object sender, EventArgs e)
        {
            try
            {
                string strMsg = this.txt_Msg.Text.Trim();
                byte[] buffer = new byte[2048];
                buffer = Encoding.Default.GetBytes(strMsg);
                int receive = socketSend.Send(buffer);  //总是用全局最新一次产生的连接的socket来发送数据
            }
            catch (Exception ex)
            {
                //MessageBox.Show("发送消息出错:" + ex.Message);
                this.txt_Log.Invoke(receiveCallBack, "发送消息出错:" + ex.Message);
            }
        }


        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_CloseConnect_Click(object sender, EventArgs e)
        {
            ////终止线程
            //if(threadReceive !=null && threadReceive.IsAlive)
            //    threadReceive.Abort();

            ////关闭socket
            //if (socketSend != null)
            //    socketSend.Close();

            //终止线程
            if (threadReceive != null)
            {
                threadReceive.Abort();
                threadReceive = null;
            }

            //关闭socket
            if (socketSend != null)
                socketSend.Close();
        }

        private void FrmClient_Load(object sender, EventArgs e)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void FrmClient_FormClosing(object sender, FormClosingEventArgs e)
        {
            btn_CloseConnect_Click(sender, e);
        }

        private void button_clear_Click(object sender, EventArgs e)
        {
            txt_Log.Text = "";
        }
    }
}
